﻿//Restriction Module v 1.0
//Written by Bugra POSTACI (c)
//August 2010

using System;
using System.Web;
using System.Web.Caching;
using System.Text.RegularExpressions;
using System.Web.Configuration;
using System.Collections.Generic; 

namespace RestrictionModuleApp
{
    public class RestrictionModule : IHttpModule
    {
        public static readonly string ConfigFile = "restrictions.xml";
        public static readonly string ConfigCacheName = "Restrictions";
        

        #region IHttpModule Members

        public void Dispose()
        {
            //clean-up code here.
        }

        public void Init(HttpApplication context)
        {
            if (WebConfigurationManager.AppSettings["RestrictionModuleActive"] != null)
            {
                string val = WebConfigurationManager.AppSettings["RestrictionModuleActive"].ToLower();
                if(val=="on")
                    context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
            }
        }

        void context_PreRequestHandlerExecute(object sender, EventArgs e)
        {
            HttpContext context = HttpContext.Current;
            RestrictionRuleCollection rules = GetRules(); 


            foreach (RestrictionRule rule in rules)
            {
                if (rule.Enabled == false) continue; 
               
                bool authFlag = rule.AuthorizeRule() ;
                bool ruleFlag = false;
                foreach (Expression exp in rule.Expressions)
                {
                    switch (exp.Type)
                    {
                        case ExpressionType.RegularExpression:
                            ruleFlag = ExecuteRegularExpression(context, rule,exp);
                            break;
                        case ExpressionType.Contains:
                            ruleFlag = ExecuteContains(context, rule,exp);
                            break;
                        case ExpressionType.StartWith:
                            ruleFlag = ExecuteStartWith(context, rule,exp);
                            break;
                        case ExpressionType.EndWith:
                            ruleFlag = ExecuteEndWith(context, rule,exp);
                            break;
                    }
                    if (ruleFlag) break; 
                }

                if (ruleFlag)
                {
                    if (rule.Action == RestrictionAction.Deny && authFlag)
                    {
                        Redirect(rule.RedirectURL); 
                    }
                    else if (rule.Action == RestrictionAction.Allow && !authFlag)
                    {
                        Redirect(rule.RedirectURL); 
                    }
                    if(!rule.ContinueRuleList)
                        break; 
                }
               
            }
        }
        #endregion


        private void Redirect(string url)
        {
            HttpContext.Current.Response.AddHeader("X-Powered-By", "Bugra Postaci 2010");
            HttpContext.Current.Response.AddHeader("RedirectionModule", "Online"); 
            HttpContext.Current.Response.Redirect(url, true);
        }

        private bool ExecuteStartWith(HttpContext context,RestrictionRule rule, Expression exp)
        {
            
            string rawCriteria = rule.GetCompareCriteria() ;
            string parameter = string.Empty; 

            if (!exp.CaseSensitive)
            {
                rawCriteria = rawCriteria.ToLower();
                parameter = exp.Parameter.ToLower();
            }
            else
            {
                parameter = exp.Parameter;
            }
            if (rawCriteria.StartsWith(parameter))
            {
                return true;
            }
            return false; 
        }
        private bool ExecuteRegularExpression(HttpContext context, RestrictionRule rule, Expression exp)
        {
           
            string rawCriteria = rule.GetCompareCriteria();
            Regex regex =null;
            if (rule.RegularExpression != null)
            {
                
                regex = rule.RegularExpression;
            }
            else
            {
                regex = new Regex(exp.Parameter);
                rule.RegularExpression = regex;
            }

            if (regex.IsMatch(rawCriteria))
            {

                return true; 
               
            }
            return false; 
        }
        private bool ExecuteContains(HttpContext context, RestrictionRule rule, Expression exp)
        {
            
            string rawCriteria = rule.GetCompareCriteria();
            string parameter = string.Empty; 

            if (!exp.CaseSensitive)
            {
                rawCriteria = rawCriteria.ToLower();
                parameter = exp.Parameter.ToLower();
            }
            else
            {
                parameter = exp.Parameter;
            }
            if (rawCriteria.Contains(parameter))
            {
                return true;
            }
            return false;
        }
        private bool ExecuteEndWith(HttpContext context, RestrictionRule rule, Expression exp)
        {
            
            string rawCriteria = rule.GetCompareCriteria(); 
            string parameter = string.Empty;
           
            if (!exp.CaseSensitive)
            {
                rawCriteria = rawCriteria.ToLower();
                parameter = exp.Parameter.ToLower();
            }
            else
            {
                parameter = exp.Parameter;
            }
            if (rawCriteria.EndsWith(parameter))
            {
                return true; 
            }
            return false;
        }

        private RestrictionRuleCollection GetRules()
        {
            HttpContext context = HttpContext.Current;
            RestrictionRuleCollection rules = null;
            string path = HttpContext.Current.Server.MapPath( @"\" + RestrictionModule.ConfigFile);
            if (context.Cache[ConfigCacheName] != null)
            {
                rules = (RestrictionRuleCollection)context.Cache[ConfigCacheName];
            }
            else
            {
                rules = RestrictionRuleCollection.LoadRules();
                CacheDependency dependency = new CacheDependency(path);
                context.Cache.Insert(ConfigCacheName, rules, dependency);

            }
            return rules;
        }
    }
}
